home *** CD-ROM | disk | FTP | other *** search
- /* xlseq.c - xlisp sequence functions */
- /* Written by Thomas Almy, based on code:
- Copyright (c) 1985, by David Michael Betz
- All Rights Reserved
- Permission is granted for unrestricted non-commercial use */
-
- #include "xlisp.h"
- #include <string.h>
-
- #ifdef COMMONLISP
-
- /* external variables */
- extern LVAL k_start,k_end,k_1start,k_1end,k_2start,k_2end;
- extern LVAL true;
-
- /* this is part of the COMMON LISP extension: */
- /* (elt seq index) -- generic sequence reference function */
- /* (map type fcn seq1 [seq2 ...]) -- generic sequence mapping function */
- /* type is one of cons, array, string, or nil */
- /* (some fcn seq1 [seq2 ...]) -- apply fcn until non-nil */
- /* also every notany and notevery */
- /* (concatenate type seq1 [seq2 ...]) -- sequence concatenation function */
- /* type is one of cons, array, or string. */
- /* (position-if pred seq) -- returns position of first match */
- /* (search seq1 seq1 &key :test :test-not :start1 :end1 :start2 :end2) --
- generic sequence searching function. */
- /* subseq reverse remove remove-if remove-if-not delete delete-if
- delete-if-not -- rewritten to allow all sequence types */
- /* find-if count-if -- previous Common Lisp extension, rewritten to allow
- all sequence types */
- /* the keyword arguments :start and :end are now valid for the remove, delete,
- find position and count functions */
-
-
- /* The author, Tom Almy, appologizes for using "goto" several places in
- this code. */
-
- #define MAXSIZE ((unsigned)-1) /* the maximum unsigned integer value */
-
- #ifdef ANSI
- static void getseqbounds(unsigned *start, unsigned *end, unsigned length,
- LVAL *startkey, LVAL *endkey)
- #else
- LOCAL VOID getseqbounds(start,end,length,startkey,endkey)
- unsigned *start, *end, length;
- LVAL *startkey, *endkey;
- #endif
- {
- LVAL arg;
- FIXTYPE temp;
-
- if (xlgkfixnum(*startkey,&arg)) {
- temp = (long)getfixnum(arg);
- if (temp < 0 || temp > length ) goto rangeError;
- *start = (unsigned)temp;
- }
- else *start = 0;
-
- if (xlgetkeyarg(*endkey, &arg) && arg != NIL) {
- if (!fixp(arg)) xlbadtype(arg);
- temp = (long)getfixnum(arg);
- if (temp < *start || temp > length) goto rangeError;
- *end = (unsigned)temp;
- }
- else *end = length;
-
- return;
- /* else there is a range error */
-
- rangeError:
- xlerror("range error",arg);
- }
-
-
-
- /* dotest1 - call a test function with one argument */
- /* this function was in xllist.c */
- #ifdef ANSI
- static int dotest1(LVAL arg, LVAL fun)
- #else
- LOCAL int dotest1(arg,fun)
- LVAL arg,fun;
- #endif
- {
- LVAL *newfp;
-
- /* create the new call frame */
- newfp = xlsp;
- pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
- pusharg(fun);
- pusharg(cvfixnum((FIXTYPE)1));
- pusharg(arg);
- xlfp = newfp;
-
- /* return the result of applying the test function */
- return (xlapply(1) != NIL);
-
- }
-
-
- /* xelt - sequence reference function */
- LVAL xelt()
- {
- LVAL seq,index;
- FIXTYPE i;
-
- /* get the sequence and the index */
-
- seq = xlgetarg();
-
- index = xlgafixnum(); i = getfixnum(index);
- if (i < 0) goto badindex;
-
- xllastarg();
-
- if (listp(seq)) { /* do like nth, but check for in range */
- /* find the ith element */
- while (consp(seq)) {
- if (i-- == 0) return (car(seq));
- seq = cdr(seq);
- }
- goto badindex; /* end of list reached first */
- }
-
-
- if (ntype(seq) == STRING) {
- if (i >= getslength(seq)-1) goto badindex;
- return (cvchar(getstringch(seq,i)));
- }
-
- if (ntype(seq)!=VECTOR) xlbadtype(seq); /* type must be array */
-
- /* range check the index */
- if (i >= getsize(seq)) goto badindex;
-
- /* return the array element */
- return (getelement(seq,(int)i));
-
- badindex:
- xlerror("index out of bounds",index);
- return (NIL); /* eliminate warnings */
- }
-
-
- /* xmap -- map function */
-
- #ifdef ANSI
- static unsigned getlength(LVAL seq)
- #else
- LOCAL unsigned getlength(seq)
- LVAL seq;
- #endif
- {
- unsigned len;
-
- if (seq == NIL) return 0;
-
- switch (ntype(seq)) {
- case STRING:
- return (unsigned)(getslength(seq) - 1);
- case VECTOR:
- return (unsigned)(getsize(seq));
- case CONS:
- len = 0;
- while (consp(seq)) {
- len++;
- seq = cdr(seq);
- }
- return len;
- default:
- xlbadtype(seq);
- return (0); /* ha ha */
- }
- }
-
-
- LVAL xmap()
- {
- LVAL *newfp, fun, lists, val, last, x, y;
- unsigned len,temp, i;
- int argc, typ;
-
- /* protect some pointers */
- xlstkcheck(3);
- xlsave(fun);
- xlsave(lists);
- xlsave(val);
-
- /* get the type of resultant */
- if ((last = xlgetarg()) == NIL) { /* nothing is returned */
- typ = 0;
- }
- else if ((typ = xlcvttype(last)) != CONS &&
- typ != STRING && typ != VECTOR) {
- xlerror("invalid result type", last);
- }
-
- /* get the function to apply and argument sequences */
- fun = xlgetarg();
- val = NIL;
- lists = xlgetarg();
- len = getlength(lists);
- argc = 1;
-
- /* check for invalid result size (actually only needed when 16bit ints)*/
- if (((int)len)<0 && (typ==STRING || typ==VECTOR)) {
- xlerror("too long",last);
- }
-
- /* build a list of argument lists */
- for (lists = last = consa(lists); moreargs(); last = cdr(last)) {
- val = xlgetarg();
- if ((temp = getlength(val)) < len) len = temp;
- argc++;
- rplacd(last,(cons(val,NIL)));
- }
-
- /* initialize the result list */
- switch (typ) {
- case VECTOR: val = newvector(len); break;
- case STRING: val = newstring(len+1); break;
- default: val = NIL; break;
- }
-
-
- /* loop through each of the argument lists */
- for (i=0;i<len;i++) {
-
- /* build an argument list from the sublists */
- newfp = xlsp;
- pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
- pusharg(fun);
- pusharg(NIL);
- for (x = lists; x != NIL ; x = cdr(x)) {
- y = car(x);
- switch (ntype(y)) {
- case CONS:
- pusharg(car(y));
- rplaca(x,cdr(y));
- break;
- case VECTOR:
- pusharg(getelement(y,i));
- break;
- case STRING:
- pusharg(cvchar(getstringch(y,i)));
- break;
- }
- }
-
- /* apply the function to the arguments */
- newfp[2] = cvfixnum((FIXTYPE)argc);
- xlfp = newfp;
- x = xlapply(argc);
-
- switch (typ) {
- case CONS:
- y = consa(x);
- if (val) rplacd(last,y);
- else val = y;
- last = y;
- break;
- case VECTOR:
- setelement(val,i,x);
- break;
- case STRING:
- if (!charp(x))
- xlerror("map function returned non-character",x);
- val->n_string[i] = getchcode(x);
- break;
- }
-
- }
-
- /* restore the stack */
- xlpopn(3);
-
- /* return the last test expression value */
- return (val);
- }
-
-
- /* every, some, notany, notevery */
-
- #define EVERY 0
- #define SOME 1
- #define NOTEVERY 2
- #define NOTANY 3
-
- #ifdef ANSI
- static LVAL xlmapwhile(int cond)
- #else
- LOCAL LVAL xlmapwhile(cond)
- int cond;
- #endif
- {
- int exitcond;
- LVAL *newfp, fun, lists, val, last, x, y;
- unsigned len,temp,i;
- int argc;
-
- /* protect some pointers */
- xlstkcheck(2);
- xlsave(fun);
- xlsave(lists);
-
- /* get the function to apply and argument sequences */
- fun = xlgetarg();
- lists = xlgetarg();
- len = getlength(lists);
- argc = 1;
-
- /* build a list of argument lists */
- for (lists = last = consa(lists); moreargs(); last = cdr(last)) {
- val = xlgetarg();
- if ((temp = getlength(val)) < len) len = temp;
- argc++;
- rplacd(last,(cons(val,NIL)));
- }
-
- switch (cond) {
- case SOME:
- case NOTANY:
- exitcond = TRUE;
- val = NIL;
- break;
- case EVERY:
- case NOTEVERY:
- exitcond = FALSE;
- val = true;
- break;
- }
-
-
- /* loop through each of the argument lists */
- for (i=0;i<len;i++) {
-
- /* build an argument list from the sublists */
- newfp = xlsp;
- pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
- pusharg(fun);
- pusharg(NIL);
- for (x = lists; x != NIL ; x = cdr(x)) {
- y = car(x);
- switch (ntype(y)) {
- case CONS:
- pusharg(car(y));
- rplaca(x,cdr(y));
- break;
- case VECTOR:
- pusharg(getelement(y,i));
- break;
- case STRING:
- pusharg(cvchar(getstringch(y,i)));
- break;
- }
- }
-
- /* apply the function to the arguments */
- newfp[2] = cvfixnum((FIXTYPE)argc);
- xlfp = newfp;
- val = xlapply(argc);
- if ((val == NIL) ^ exitcond) break;
- }
-
- if ((cond == NOTANY) | (cond == NOTEVERY)) {
- if (val == NIL)
- val = true;
- else
- val = NIL;
- }
-
-
- /* restore the stack */
- xlpopn(2);
-
- /* return the last test expression value */
- return (val);
- }
-
-
- LVAL xevery()
- {
- return xlmapwhile(EVERY);
- }
-
- LVAL xsome()
- {
- return xlmapwhile(SOME);
- }
-
- LVAL xnotany()
- {
- return xlmapwhile(NOTANY);
- }
-
- LVAL xnotevery()
- {
- return xlmapwhile(NOTEVERY);
- }
-
- /* xconcatenate - concatenate a bunch of sequences */
- /* replaces (and extends) strcat, now a macro */
- #ifdef ANSI
- static int calclength(void)
- #else
- LOCAL int calclength()
- #endif
- {
- LVAL tmp, *saveargv;
- int saveargc;
- int len;
-
- /* save the argument list */
- saveargv = xlargv;
- saveargc = xlargc;
-
- /* find the length of the new string or vector */
- for (len = 0; moreargs(); ) {
- tmp = xlgetarg();
- len += getlength(tmp);
-
- if (len < 0) xlerror("too long",tmp); /*trick to check for overflow*/
- }
-
- /* restore the argument list */
- xlargv = saveargv;
- xlargc = saveargc;
-
- return len;
- }
-
-
- #ifdef ANSI
- static LVAL cattostring(void)
- #else
- LOCAL LVAL cattostring()
- #endif
- {
- LVAL tmp,temp,val;
- char *str;
- int len,i;
-
- /* find resulting length -- also validates argument types */
- len = calclength();
-
- /* create the result string */
- val = newstring(len+1);
- str = getstring(val);
-
- /* combine the strings */
- while (moreargs()) {
- tmp = nextarg();
- if (tmp != NIL) switch (ntype(tmp)) {
- case STRING:
- len = getslength(tmp)-1;
- memcpy((char *)str, (char *)getstring(tmp), len);
- str += len;
- break;
- case VECTOR:
- len = getsize(tmp);
- for (i = 0; i < len; i++) {
- temp = getelement(tmp,i);
- if (!charp(temp)) goto failed;
- *str++ = getchcode(temp);
- }
- break;
- case CONS:
- while (consp(tmp)) {
- temp = car(tmp);
- if (!charp(temp)) goto failed;
- *str++ = getchcode(temp);
- tmp = cdr(tmp);
- }
- break;
- }
- }
-
- *str = 0; /* delimit string (why, I don't know!) */
-
- /* return the new string */
- return (val);
-
- failed:
- xlerror("cannot make into string", tmp);
- return (NIL); /* avoid warning message */
- }
-
- #ifdef ANSI
- static LVAL cattovector(void)
- #else
- LOCAL LVAL cattovector()
- #endif
- {
- LVAL tmp,val;
- LVAL *vect;
- int len,i;
-
- /* find resulting length -- also validates argument types */
- len = calclength();
-
- /* create the result vector */
- val = newvector(len);
- vect = &val->n_vdata[0];
-
- /* combine the vectors */
- while (moreargs()) {
- tmp = nextarg();
- if (tmp != NIL) switch (ntype(tmp)) {
- case VECTOR:
- len = getsize(tmp);
- memcpy(vect, &getelement(tmp,0), len*sizeof(LVAL));
- vect += len;
- break;
- case STRING:
- len = getslength(tmp)-1;
- for (i = 0; i < len; i++) {
- *vect++ = cvchar(getstringch(tmp,i));
- }
- break;
- case CONS:
- while (consp(tmp)) {
- *vect++ = car(tmp);
- tmp = cdr(tmp);
- }
- break;
- }
- }
-
- /* return the new vector */
- return (val);
- }
-
- #ifdef ANSI
- static LVAL cattocons(void)
- #else
- LOCAL LVAL cattocons()
- #endif
- {
- LVAL val,tmp,next,last=NIL;
- int len,i;
-
- xlsave1(val); /* protect against GC */
-
- /* combine the lists */
- while (moreargs()) {
- tmp = nextarg();
- if (tmp != NIL) switch (ntype(tmp)) {
- case CONS:
- while (consp(tmp)) {
- next = consa(car(tmp));
- if (val) rplacd(last,next);
- else val = next;
- last = next;
- tmp = cdr(tmp);
- }
- break;
- case VECTOR:
- len = getsize(tmp);
- for (i = 0; i<len; i++) {
- next = consa(getelement(tmp,i));
- if (val) rplacd(last,next);
- else val = next;
- last = next;
- }
- break;
- case STRING:
- len = getslength(tmp) - 1;
- for (i = 0; i < len; i++) {
- next = consa(cvchar(getstringch(tmp,i)));
- if (val) rplacd(last,next);
- else val = next;
- last = next;
- }
- break;
- default:
- xlbadtype(tmp); break; /* need default because no precheck*/
- }
- }
-
- xlpop();
-
- return (val);
-
- }
-
-
- LVAL xconcatenate()
- {
- LVAL tmp;
-
- switch (xlcvttype(tmp = xlgetarg())) { /* target type of data */
- case CONS: return cattocons();
- case STRING: return cattostring();
- case VECTOR: return cattovector();
- default: xlerror("invalid result type", tmp);
- return (NIL); /* avoid warning */
- }
- }
-
- /* xsubseq - return a subsequence -- new version */
-
- LVAL xsubseq()
- {
- unsigned start,end,len;
- FIXTYPE temp;
- int srctype;
- LVAL src,dst;
- LVAL next,last=NIL;
-
- /* get sequence */
- src = xlgetarg();
- if (listp(src)) srctype = CONS;
- else srctype=ntype(src);
-
-
- /* get length */
- switch (srctype) {
- case STRING:
- len = getslength(src) - 1;
- break;
- case VECTOR:
- len = getsize(src);
- break;
- case CONS:
- dst = src; /* use dst as temporary */
- len = 0;
- while (consp(dst)) {len++; dst = cdr(dst);}
- break;
- default:
- xlbadtype(src);
- }
-
- /* get the starting position */
- dst = xlgafixnum(); temp = (int)getfixnum(dst);
- if (temp < 0 || temp > len)
- xlerror("sequence index out of bounds",dst);
- start = (unsigned) temp;
-
- /* get the ending position */
- if (moreargs()) {
- dst = nextarg();
- if (dst == NIL) end = len;
- else if (fixp(dst)) {
- temp = (int)getfixnum(dst);
- if (temp < start || temp > len)
- xlerror("sequence index out of bounds",dst);
- end = (unsigned) temp;
- }
- else xlbadtype(dst);
- }
- else
- end = len;
- xllastarg();
-
- len = end - start;
-
- switch (srctype) { /* do the subsequencing */
- case STRING:
- dst = newstring(len+1);
- memcpy(getstring(dst), getstring(src)+start, len);
- dst->n_string[len] = 0;
- break;
- case VECTOR:
- dst = newvector(len);
- memcpy(dst->n_vdata, &src->n_vdata[start], sizeof(LVAL)*len);
- break;
- case CONS:
- xlsave1(dst);
- while (start--) src = cdr(src);
- while (len--) {
- next = consa(car(src));
- if (dst) rplacd(last,next);
- else dst = next;
- last = next;
- src = cdr(src);
- }
- xlpop();
- break;
- }
-
- /* return the substring */
- return (dst);
- }
-
-
- /* xnreverse -- built-in function nreverse (destructive reverse) */
- LVAL xnreverse()
- {
- LVAL seq,val,next;
- unsigned int i,j;
- int ival;
-
- /* get the sequence to reverse */
- seq = xlgetarg();
- xllastarg();
-
- if (seq == NIL) return (NIL); /* empty argument */
-
- switch (ntype(seq)) {
- case CONS:
- val = NIL;
- while (consp(seq)) {
- next = cdr(seq);
- rplacd(seq,val);
- val = seq;
- seq = next;
- }
- break;
- case VECTOR:
- for (i = 0, j = getlength(seq)-1; i < j; i++, j--) {
- val = getelement(seq,i);
- setelement(seq,i,getelement(seq,j));
- setelement(seq,j,val);
- }
- return seq;
- break;
- case STRING:
- for (i = 0, j=getslength(seq)-2 ; i < j; i++, j--) {
- ival = seq->n_string[i];
- seq->n_string[i] = seq->n_string[j];
- seq->n_string[j] = ival;
- }
- return seq;
- break;
- default:
- xlbadtype(seq); break;
- }
-
- /* return the sequence */
- return (val);
- }
-
- /* xreverse - built-in function reverse -- new version */
- LVAL xreverse()
- {
- LVAL seq,val;
- int i,len;
-
- /* get the sequence to reverse */
- seq = xlgetarg();
- xllastarg();
-
- if (seq == NIL) return (NIL); /* empty argument */
-
- switch (ntype(seq)) {
- case CONS:
- /* protect pointer */
- xlsave1(val);
-
- /* append each element to the head of the result list */
- for (val = NIL; consp(seq); seq = cdr(seq))
- val = cons(car(seq),val);
-
- /* restore the stack */
- xlpop();
- break;
- case VECTOR:
- len = getsize(seq);
- val = newvector(len);
- for (i = 0; i < len; i++)
- setelement(val,i,getelement(seq,len-i-1));
- break;
- case STRING:
- len = getslength(seq) - 1;
- val = newstring(len+1);
- for (i = 0; i < len; i++)
- val->n_string[i] = seq->n_string[len-i-1];
- val->n_string[len] = 0;
- break;
- default:
- xlbadtype(seq); break;
- }
-
- /* return the sequence */
- return (val);
- }
-
-
- /* remif - common code for 'remove', 'remove-if', and 'remove-if-not' */
- #ifdef ANSI
- static LVAL remif(int tresult, int expr)
- #else
- LOCAL LVAL remif(tresult,expr)
- int tresult,expr;
- #endif
- {
- LVAL x,seq,fcn,val,last,next;
- unsigned i,j,l;
- unsigned start,end;
-
- if (expr) {
- /* get the expression to remove and the sequence */
- x = xlgetarg();
- seq = xlgetarg();
- xltest(&fcn,&tresult);
- }
- else {
- /* get the function and the sequence */
- fcn = xlgetarg();
- seq = xlgetarg();
- /* xllastarg(); */
- }
-
- if (seq == NIL) return NIL;
-
- getseqbounds(&start,&end,MAXSIZE,&k_start,&k_end);
-
- /* protect some pointers */
- xlstkcheck(2);
- xlprotect(fcn);
- xlsave(val);
-
- /* remove matches */
-
- switch (ntype(seq)) {
- case CONS:
- for (; consp(seq); seq = cdr(seq)) {
- long s=start, l=end-start;
- /* check to see if this element should be deleted */
- /* force copy if count, as specified by end, is exhausted */
- if (s-- > 0 || l-- <= 0 ||
- (expr?dotest2(x,car(seq),fcn)
- :dotest1(car(seq),fcn)) != tresult) {
- next = consa(car(seq));
- if (val) rplacd(last,next);
- else val = next;
- last = next;
- }
- }
- break;
- case VECTOR:
- val = newvector(l=getlength(seq));
- for (i=j=0; i < l; i++) {
- if (i < start || i >= end || /* copy if out of range */
- (expr?dotest2(x,getelement(seq,i),fcn)
- :dotest1(getelement(seq,i),fcn)) != tresult) {
- setelement(val,j++,getelement(seq,i));
- }
- }
- if (l != j) { /* need new, shorter result -- too bad */
- fcn = val; /* save value in protected cell */
- val = newvector(j);
- memcpy(val->n_vdata, fcn->n_vdata, j*sizeof(LVAL));
- }
- break;
- case STRING:
- l = getslength(seq)-1;
- val = newstring(l+1);
- for (i=j=0; i < l; i++) {
- if (i < start || i >= end || /* copy if out of range */
- (expr?dotest2(x,cvchar(getstringch(seq,i)),fcn)
- :dotest1(cvchar(getstringch(seq,i)),fcn)) != tresult) {
- val->n_string[j++] = seq->n_string[i];
- }
- }
- if (l != j) { /* need new, shorter result -- too bad */
- fcn = val; /* save value in protected cell */
- val = newstring(j+1);
- memcpy(val->n_string, fcn->n_string, j*sizeof(char));
- val->n_string[j] = 0;
- }
- break;
- default:
- xlbadtype(seq); break;
- }
-
-
- /* restore the stack */
- xlpopn(2);
-
- /* return the updated sequence */
- return (val);
- }
-
- /* xremif - built-in function 'remove-if' -- enhanced version */
- LVAL xremif()
- {
- return (remif(TRUE,FALSE));
- }
-
- /* xremifnot - built-in function 'remove-if-not' -- enhanced version */
- LVAL xremifnot()
- {
- return (remif(FALSE,FALSE));
- }
-
- /* xremove - built-in function 'remove' -- enhanced version */
-
- LVAL xremove()
- {
- return (remif(TRUE,TRUE));
- }
-
-
- /* delif - common code for 'delete', 'delete-if', and 'delete-if-not' */
- #ifdef ANSI
- static LVAL delif(int tresult, int expr)
- #else
- LOCAL LVAL delif(tresult,expr)
- int tresult,expr;
- #endif
- {
- LVAL x,seq,fcn,last,val;
- unsigned i,j,l;
- unsigned start,end;
-
- if (expr) {
- /* get the expression to delete and the sequence */
- x = xlgetarg();
- seq = xlgetarg();
- xltest(&fcn,&tresult);
- }
- else {
- /* get the function and the sequence */
- fcn = xlgetarg();
- seq = xlgetarg();
- /* xllastarg(); */
- }
-
- if (seq == NIL) return NIL;
-
- getseqbounds(&start,&end,MAXSIZE,&k_start,&k_end);
-
- /* protect a pointer */
- xlstkcheck(1);
- xlprotect(fcn);
-
-
- /* delete matches */
-
- switch (ntype(seq)) {
- case CONS:
- end -= start; /* gives length */
- /* delete leading matches */
- while (consp(seq)) {
- if (start-- > 0 || (expr?dotest2(x,car(seq),fcn)
- :dotest1(car(seq),fcn)) != tresult)
- break;
- seq = cdr(seq);
- }
- val = last = seq;
-
- /* delete embedded matches */
- if (consp(seq)) {
-
- /* skip the first non-matching element */
- seq = cdr(seq);
-
- for (;consp(seq) && start-- > 0;seq=cdr(seq));
-
- /* look for embedded matches */
- while (consp(seq)) {
-
- /* check to see if this element should be deleted */
- if (end-- > 0 &&
- (expr?dotest2(x,car(seq),fcn)
- :dotest1(car(seq),fcn)) == tresult)
- rplacd(last,cdr(seq));
- else
- last = seq;
-
- /* move to the next element */
- seq = cdr(seq);
- }
- }
- break;
- case VECTOR:
- l = getlength(seq);
- for (i=j=0; i < l; i++) {
- if (i < start || i >= end || /* copy if out of range */
- (expr?dotest2(x,getelement(seq,i),fcn)
- :dotest1(getelement(seq,i),fcn)) != tresult) {
- if (i != j) setelement(seq,j,getelement(seq,i));
- j++;
- }
- }
- if (l != j) { /* need new, shorter result -- too bad */
- fcn = seq; /* save value in protected cell */
- seq = newvector(j);
- memcpy(seq->n_vdata, fcn->n_vdata, j*sizeof(LVAL));
- }
- val = seq;
- break;
- case STRING:
- l = getslength(seq)-1;
- for (i=j=0; i < l; i++) {
- if (i < start || i >= end || /* copy if out of range */
- (expr?dotest2(x,cvchar(getstringch(seq,i)),fcn)
- :dotest1(cvchar(getstringch(seq,i)),fcn)) != tresult) {
- if (i != j) seq->n_string[j] = seq->n_string[i];
- j++;
- }
- }
- if (l != j) { /* need new, shorter result -- too bad */
- fcn = seq; /* save value in protected cell */
- seq = newstring(j+1);
- memcpy(seq->n_string, fcn->n_string, j*sizeof(char));
- seq->n_string[j] = 0;
- }
- val = seq;
- break;
- default:
- xlbadtype(seq); break;
- }
-
-
- /* restore the stack */
- xlpop();
-
- /* return the updated sequence */
- return (val);
- }
-
- /* xdelif - built-in function 'delete-if' -- enhanced version */
- LVAL xdelif()
- {
- return (delif(TRUE,FALSE));
- }
-
- /* xdelifnot - built-in function 'delete-if-not' -- enhanced version */
- LVAL xdelifnot()
- {
- return (delif(FALSE,FALSE));
- }
-
- /* xdelete - built-in function 'delete' -- enhanced version */
-
- LVAL xdelete()
- {
- return (delif(TRUE,TRUE));
- }
-
- #ifdef ADDEDTAA
- /* xcountif - built-in function 'count-if TAA MOD addition */
- LVAL xcountif()
- {
- unsigned counter=0;
- unsigned i,l;
- unsigned start,end;
- LVAL seq, fcn;
-
-
- /* get the arguments */
- fcn = xlgetarg();
- seq = xlgetarg();
- /* xllastarg(); */
-
- if (seq == NIL) return (cvfixnum((FIXTYPE)0));
-
- getseqbounds(&start,&end,MAXSIZE,&k_start,&k_end);
-
- xlstkcheck(1);
- xlprotect(fcn);
-
- /* examine arg and count */
- switch (ntype(seq)) {
- case CONS:
- end -= start;
- for (; consp(seq) && start-- > 0; seq = cdr(seq));
- for (; consp(seq); seq = cdr(seq))
- if (end-- > 0 && dotest1(car(seq),fcn)) counter++;
- break;
- case VECTOR:
- l = getlength(seq);
- if (end < l) l = end;
- for (i=start; i < l; i++)
- if (dotest1(getelement(seq,i),fcn)) counter++;
- break;
- case STRING:
- l = getslength(seq)-1;
- if (end < l) l = end;
- for (i=start; i < l; i++)
- if (dotest1(cvchar(getstringch(seq,i)),fcn)) counter++;
- break;
- default:
- xlbadtype(seq); break;
- }
-
- xlpop();
-
- return (cvfixnum((FIXTYPE)counter));
- }
-
- /* xfindif - built-in function 'find-if' TAA MOD */
- LVAL xfindif()
- {
- LVAL seq, fcn, val;
- unsigned start,end;
- unsigned i,l;
-
- fcn = xlgetarg();
- seq = xlgetarg();
- /* xllastarg(); */
-
- if (seq == NIL) return NIL;
-
- getseqbounds(&start,&end,MAXSIZE,&k_start,&k_end);
-
- xlstkcheck(1);
- xlprotect(fcn);
-
- switch (ntype(seq)) {
- case CONS:
- end -= start;
- for (; consp(seq) && start-- > 0; seq = cdr(seq));
- for (; consp(seq); seq = cdr(seq)) {
- if (end-- > 0 && dotest1(val=car(seq), fcn)) goto fin;
- }
- break;
- case VECTOR:
- l = getlength(seq);
- if (end < l) l = end;
- for (i=start; i < l; i++)
- if (dotest1(val=getelement(seq,i),fcn)) goto fin;
- break;
- case STRING:
- l = getslength(seq)-1;
- if (end < l) l = end;
- for (i=start; i < l; i++)
- if (dotest1(val=cvchar(getstringch(seq,i)),fcn)) goto fin;
- break;
- default:
- xlbadtype(seq); break;
- }
-
- val = NIL; /* not found */
-
- fin:
- xlpop();
- return (val);
- }
-
- /* xpositionif - built-in function 'position-if' TAA MOD */
- LVAL xpositionif()
- {
- LVAL seq, fcn;
- unsigned start,end;
- unsigned count;
- unsigned i,l;
-
- fcn = xlgetarg();
- seq = xlgetarg();
- /* xllastarg(); */
-
- if (seq == NIL) return NIL;
-
- getseqbounds(&start,&end,MAXSIZE,&k_start,&k_end);
-
- xlstkcheck(1);
- xlprotect(fcn);
-
- switch (ntype(seq)) {
- case CONS:
- end -= start;
- count = start;
- for (; consp(seq) && start-- > 0; seq = cdr(seq));
- for (; consp(seq); seq = cdr(seq)) {
- if ((end-- > 0) && dotest1(car(seq), fcn)) goto fin;
- count++;
- }
- break;
- case VECTOR:
- l = getlength(seq);
- if (end < l) l = end;
- for (i=start; i < l; i++)
- if (dotest1(getelement(seq,i),fcn)) {
- count = i;
- goto fin;
- }
- break;
- case STRING:
- l = getslength(seq)-1;
- if (end < l) l = end;
- for (i=start; i < l; i++)
- if (dotest1(cvchar(getstringch(seq,i)),fcn)) {
- count = i;
- goto fin;
- }
- break;
- default:
- xlbadtype(seq); break;
- }
-
- xlpop(); /* not found */
- return(NIL);
-
- fin: /* found */
- xlpop();
- return (cvfixnum((FIXTYPE)count));
- }
- #endif
-
- /* xsearch -- search function */
-
- LVAL xsearch()
- {
- LVAL seq1, seq2, fcn, temp1, temp2;
- unsigned start1, start2, end1, end2, len1, len2;
- unsigned i,j;
- int tresult,typ1, typ2;
-
- /* get the sequences */
- seq1 = xlgetarg();
- len1 = getlength(seq1);
- seq2 = xlgetarg();
- len2 = getlength(seq2);
-
- /* test/test-not args? */
- xltest(&fcn,&tresult);
-
- /* check for start/end keys */
- getseqbounds(&start1,&end1,len1,&k_1start,&k_1end);
- getseqbounds(&start2,&end2,len2,&k_2start,&k_2end);
-
- if (end2 - 1 - (end1 - start1) > len2) {
- end2 = len2 + 1 + (end1 - start1);
- if (end2 < start2) end2 = start2;
- }
-
- len1 = end1 - start1; /* calc lengths of sequences to test */
-
- typ1 = ntype(seq1);
- typ2 = ntype(seq2);
-
- xlstkcheck(1);
- xlprotect(fcn);
-
- if (typ1 == CONS) { /* skip leading section of sequence 1 if a cons */
- j = start1;
- while (j--) seq1 = cdr(seq1);
- }
-
- if (typ2 == CONS) { /* second string is cons */
- i = start2; /* skip leading section of string 2 */
- while (start2--) seq2 = cdr(seq2);
-
- for (;i<end2;i++) {
- temp2 = seq2;
- if (typ1 == CONS) {
- temp1 = seq1;
- for (j = start1; j < end1; j++) {
- if (dotest2(car(temp1),car(temp2),fcn) != tresult)
- goto next1;
- temp1 = cdr(temp1);
- temp2 = cdr(temp2);
- }
- }
- else {
- for (j = start1; j < end1; j++) {
- if (dotest2(typ1 == VECTOR ? getelement(seq1,j) :
- cvchar(getstringch(seq1,j)), car(temp2), fcn) != tresult)
- goto next1;
- temp2 = cdr(temp2);
- }
- }
- xlpop();
- return cvfixnum(i);
- next1: /* continue */
- seq2 = cdr(seq2);
- }
- }
-
- else for (i = start2; i < end2 ; i++) { /* second string is array/string */
- if (typ1 == CONS) {
- temp1 = seq1;
- for (j = 0; j < len1; j++) {
- if (dotest2(car(temp1),
- typ2 == VECTOR ? getelement(seq2,i+j)
- : cvchar(getstringch(seq2,i+j)),
- fcn) != tresult)
- goto next2;
- temp1 = cdr(temp1);
- }
- }
- else for (j=start1; j < end1; j++) {
- if (dotest2(typ1 == VECTOR ? getelement(seq1,j) : cvchar(getstringch(seq1,j)),
- typ2 == VECTOR ? getelement(seq2,i+j-start1) : cvchar(getstringch(seq2,i+j-start1)), fcn) != tresult)
- goto next2;
- }
- xlpop();
- return cvfixnum(i);
- next2:; /* continue */
- }
-
- xlpop();
- return (NIL); /*no match*/
-
- }
-
-
- #endif
-
-